#set( $symbol_pound = '#' )
#set( $symbol_dollar = '$' )
#set( $symbol_escape = '\' )
package ${package}.stream;

import lombok.Data;
import lombok.experimental.Accessors;

import java.io.Serializable;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Comparator;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.NoSuchElementException;
import java.util.Objects;
import java.util.Optional;
import java.util.Set;
import java.util.Spliterator;
import java.util.Spliterators;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ForkJoinPool;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.function.BiConsumer;
import java.util.function.BiFunction;
import java.util.function.BinaryOperator;
import java.util.function.Consumer;
import java.util.function.Function;
import java.util.function.Predicate;
import java.util.function.Supplier;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import java.util.stream.StreamSupport;

public interface Seq<T> {

    void consumer(Consumer<T> consumer);

    /**
     * 实体转换
     *
     * @param function
     * @param <E>
     * @return
     */
    default <E> Seq<E> map(Function<T, E> function) {
        return consumer -> consumer(t -> consumer.accept(function.apply(t)));
    }

    /**
     * 扁平化实体转换
     *
     * @param function
     * @param <E>
     * @return
     */
    default <E> Seq<E> flatMap(Function<T, Seq<E>> function) {
        return consumer -> consumer(t -> function.apply(t).consumer(consumer));
    }

    /**
     * 过滤
     *
     * @param predicate
     * @return
     */
    default Seq<T> filter(Predicate<T> predicate) {
        return consumer -> consumer(t -> {
            if (predicate.test(t)) {
                consumer.accept(t);
            }
        });
    }

    /**
     * 遍历
     *
     * @param consumer
     * @return
     */
    default Seq<T> peek(Consumer<T> consumer) {
        return con -> consumer(t -> {
            consumer.andThen(con);
        });
    }

    static void stop() {
        throw StopException.INSTANCE;
    }

    class StopException extends RuntimeException {
        public static final StopException INSTANCE = new StopException();

        private StopException() {
        }

        @Override
        public synchronized Throwable fillInStackTrace() {
            return this;
        }
    }

    default void consumerTillStop(Consumer<T> consumer) {
        try {
            consumer(consumer);
        } catch (StopException e) {
            //do nothing
        }
    }

    /**
     * 限制数量
     *
     * @param limit
     * @return
     */
    default Seq<T> limit(int limit) {
        if (limit < 0) {
            throw new IllegalArgumentException("limit must be greater than 0");
        }
        int[] arr = {limit};
        return consumer -> consumerTillStop(t -> {
            if (arr[0]-- > 0) {
                consumer.accept(t);
            } else {
                stop();
            }
        });
    }

    /**
     * 分割
     *
     * @param size
     * @return
     */
    default Seq<Seq<T>> partition(int size) {
        if (size < 1) {
            throw new IllegalArgumentException("size must be greater than 0");
        }
        int[] arr = {size};
        List<T> list = new ArrayList<>(size);
        List<List<T>> listArrayList = new ArrayList<>(1);
        listArrayList.add(list);
        return consumer -> {
            consumerTillStop(t -> {
                if (arr[0] == 0) {
                    consumer.accept(Seq.of(listArrayList.get(0)));
                    listArrayList.set(0, new ArrayList<>(size));
                    arr[0] = size;
                }
                listArrayList.get(0).add(t);
                arr[0]--;
            });
            if (!listArrayList.get(0).isEmpty()) {
                consumer.accept(Seq.of(listArrayList.get(0)));
            }
        };
    }

    /**
     * 跳过skip元素
     *
     * @param skip
     * @return
     */
    default Seq<T> skip(int skip) {
        if (skip < 0) {
            throw new IllegalArgumentException("skip must be greater than 0");
        }
        int[] arr = {skip};
        return consumer -> consumer(t -> {
            if (arr[0]-- > 0) {
                return;
            }
            consumer.accept(t);
        });
    }

    /**
     * 满足条件时,获取limit元素停止
     *
     * @param predicate
     * @param limit
     * @return
     */
    default Seq<T> takeWhile(Predicate<T> predicate, int limit) {
        if (limit < 0) {
            throw new IllegalArgumentException("limit must be greater than 0");
        }
        int[] arr = {limit};
        return consumer -> consumerTillStop(t -> {
            if (predicate.test(t) && arr[0]-- > 0) {
                consumer.accept(t);
                return;
            }
            if (arr[0] <= 0) {
                stop();
            }
        });
    }

    /**
     * 流与一个iterable元素两两聚合，然后转换为一个新的流
     *
     * @param iterable
     * @param biFunction
     * @param <E>
     * @param <R>
     * @return
     */
    default <E, R> Seq<R> zip(Iterable<E> iterable, BiFunction<T, E, R> biFunction) {
        return consumer -> {
            iterable.forEach(e -> consumer(t -> consumer.accept(biFunction.apply(t, e))));
        };
    }

    /**
     * 排序
     *
     * @param comparator
     * @return
     */
    default Seq<T> sort(Comparator<T> comparator) {
        List<T> list = toList();
        list.sort(comparator);
        return Seq.of(list)::peek;
    }

    /**
     * 去重
     *
     * @return
     */
    default Seq<T> distinct() {
        Set<T> set = new HashSet<>();
        return consumer -> consumerTillStop(t -> {
            if (set.add(t)) {
                consumer.accept(t);
            }
        });
    }

    /**
     * 分段处理
     *
     * @param firstSegmentSize
     * @param firstFun
     * @param secondSegmentSize
     * @param secondSegFun
     * @param lastSegFun
     * @param <E>
     * @return
     */
    default <E> Seq<E> segmentMap(int firstSegmentSize, Function<T, E> firstFun, int secondSegmentSize, Function<T, E> secondSegFun, Function<T, E> lastSegFun) {
        return consumer -> {
            int[] arr = {0};
            consumerTillStop(t -> {
                arr[0]++;
                if (arr[0] <= firstSegmentSize) {
                    if (Objects.isNull(firstFun)) {
                        return;
                    }
                    consumer.accept(firstFun.apply(t));
                } else if (arr[0] <= secondSegmentSize) {
                    if (Objects.isNull(lastSegFun)) {
                        return;
                    }
                    consumer.accept(secondSegFun.apply(t));
                } else {
                    if (Objects.isNull(lastSegFun)) {
                        return;
                    }
                    consumer.accept(lastSegFun.apply(t));
                }
            });
        };
    }

    /**
     * 异步消费
     *
     * @return
     */
    default Seq<T> asyncConsumer() {
        ForkJoinPool forkJoinPool = ForkJoinPool.commonPool();
        return con -> consumer(t -> CompletableFuture.runAsync(() -> {
            con.accept(t);
        }, forkJoinPool));
    }

    /**
     * 生成seq
     *
     * @param ts
     * @param <T>
     * @return
     */
    static <T> Seq<T> of(T... ts) {
        if(Objects.isNull(ts)){
            return empty();
        }
        return consumer -> {
            for (T t : ts) {
                consumer.accept(t);
            }
        };
    }

    /**
     * 生成seq
     *
     * @param t
     * @param <T>
     * @return
     */
    static <T> Seq<T> of(T t) {
        return consumer -> consumer.accept(t);
    }

    /**
     * 生成seq
     *
     * @param ts
     * @param <T>
     * @return
     */
    static <T> Seq<T> of(Iterable<T> ts) {
        if(Objects.isNull(ts)){
            return empty();
        }
        return consumer -> {
            for (T t : ts) {
                consumer.accept(t);
            }
        };
    }

    /**
     * stream生成seq
     *
     * @param stream
     * @param <T>
     * @return
     */
    static <T> Seq<T> of(Stream<T> stream) {
        if(Objects.isNull(stream)){
            return empty();
        }
        return stream::forEach;
    }

    /**
     * 生成空seq
     *
     * @param <T>
     * @return
     */
    static <T> Seq<T> empty() {
        return consumer -> {
        };
    }

    /**
     * seq转换stream
     * 这种操作也会有一些限制，没法再使用parallel方法将其转为并发流，也不能用limit方法限制数量。
     * 不过除此以外，像map, filter, flatMap, forEach, collect等等方法，只要不涉及流的中断，都可以正常使用
     *
     * @param seq
     * @param <T>
     * @return
     */
    static <T> Stream<T> stream(Seq<T> seq) {
        Iterator<T> iterator = new Iterator<T>() {
            @Override
            public boolean hasNext() {
                throw new NoSuchElementException();
            }

            @Override
            public T next() {
                throw new NoSuchElementException();
            }

            @Override
            public void forEachRemaining(Consumer<? super T> action) {
                seq.consumer(action::accept);
            }
        };
        return StreamSupport.stream(
                Spliterators.spliteratorUnknownSize(iterator, Spliterator.ORDERED),
                false);
    }

    default Seq<T> forEachTree(Function<T, Seq<T>> function){
        return consumer -> consumer(t -> scanTree(consumer, t, function));
    }
    /**
     * 树遍历，二叉树遍历（ofTree(node, n -> Seq.of(n.left, n.right))）
     *
     * @param node
     * @param function
     * @param <N>
     * @return
     */
    static <N> Seq<N> scanTree(N node, Function<N, Seq<N>> function) {
        return consumer -> scanTree(consumer, node, function);
    }

    static <N> void scanTree(Consumer<N> consumer, N node, Function<N, Seq<N>> function) {
        consumer.accept(node);
        function.apply(node).consumer(con -> {
            if (con == null) {
                return;
            }
            scanTree(consumer, con, function);
        });
    }

    /**
     * 生成树
     *
     * @param treeList
     * @param idFun
     * @param parentIdFun
     * @param rootIdFun
     * @param childFun
     * @param <N>
     * @param <R>
     * @return
     */
    static <N, R> Seq<N> genTree(List<N> treeList, Function<N, R> idFun, Function<N, R> parentIdFun, Predicate<N> rootIdFun, BiConsumer<N, List<N>> childFun) {
        return of(ofTree(treeList, idFun, parentIdFun, rootIdFun, childFun));
    }

    /**
     * 生成树
     *
     * @param seq
     * @param <N>
     */
    static <N, R> List<N> ofTree(List<N> treeList, Function<N, R> idFun, Function<N, R> parentIdFun, Predicate<N> rootIdFun, BiConsumer<N, List<N>> childFun) {
        if (Objects.isNull(treeList) || treeList.isEmpty()) {
            return new ArrayList<>();
        }
        Map<R, List<N>> treeMap = treeList.stream().collect(Collectors.groupingBy(parentIdFun));
        List<N> nList = treeList.stream()
                .filter(rootIdFun)
                .collect(Collectors.toList());
        recursionTree(nList, idFun, treeMap, childFun);
        return nList;
    }

    static <N, R> void recursionTree(List<N> treeList, Function<N, R> idFun, Map<R, List<N>> treeMap, BiConsumer<N, List<N>> childFun) {
        if (Objects.isNull(treeList) || treeList.isEmpty()) {
            return;
        }
        treeList.forEach(n -> {
            List<N> nList = treeMap.get(idFun.apply(n));
            childFun.accept(n, nList);
            recursionTree(nList, idFun, treeMap, childFun);
        });
    }

    @Data
    @Accessors(chain = true)
    public class TreeNode implements Serializable {
        private static final long serialVersionUID = 1L;
        /**
         * 节点id
         */
        private String id;
        /**
         * 父节点id
         */
        private String parentId;
        /**
         * 节点名称
         */
        private String name;
        /**
         * 节点类型
         */
        private String type;
        /**
         * 节点层级
         */
        private Integer level;
        /**
         * 子节点
         */
        private List<TreeNode> children;
    }

    /**
     * 生成无限seq
     *
     * @param function
     * @return
     */
    static Seq<Integer> infiniteSeq(Function<Integer, Integer> function) {
        return consumer -> {
            int i = 0;
            while (true) {
                consumer.accept(function.apply(i++));
            }
        };
    }

    /**
     * 拼接字符串
     *
     * @param delimiter
     * @param function
     * @return
     */
    default String join(String delimiter, Function<T, String> function) {
        StringBuilder stringBuilder = new StringBuilder();
        consumer(t -> {
            stringBuilder.append(function.apply(t)).append(delimiter);
        });
        if (stringBuilder.length() == 0) {
            return "";
        }
        return stringBuilder.substring(0, stringBuilder.length() - delimiter.length());
    }

    /**
     * .
     * 转换为list
     *
     * @return
     */
    default List<T> toList() {
        return toCollection(ArrayList::new);
    }

    /**
     * 遍历
     *
     * @param consumer
     */
    default void foreach(Consumer<T> consumer) {
        consumer(consumer);
    }

    /**
     * 转换为set
     *
     * @return
     */
    default Set<T> toSet() {
        return toCollection(HashSet::new);
    }

    default <C extends Collection<T>> C toCollection(Supplier<C> supplier) {
        C collection = supplier.get();
        consumer(collection::add);
        return collection;
    }

    default <C extends Collection<T>> C toCollection(Reduce<T, C, C> reduce) {
        Supplier<C> supplier = reduce.supplier();
        BiConsumer<C, T> accumulator = reduce.accumulator();
        C collection = supplier.get();
        consumer(t -> accumulator.accept(collection, t));
        return collection;
    }

    default <E, R> Map<E, R> toMap(Function<? super T, ? extends E> keyFunction, Function<? super T, ? extends R> valueFunction) {
        return toMap(keyFunction, HashMap::new, valueFunction, (k1, k2) -> k2);
    }

    default <E, R> Map<E, R> toMap(Function<? super T, ? extends E> keyFunction, Function<? super T, ? extends R> valueFunction, BiFunction<R, R, R> mergeFunction) {
        return toMap(keyFunction, HashMap::new, valueFunction, mergeFunction);
    }

    /**
     * 转换为map
     *
     * @param keyFunction
     * @param valueFunction
     * @param <E>
     * @param <R>
     * @return
     */
    default <E, R, M extends Map<E, R>> Map<E, R> toMap(Function<? super T, ? extends E> keyFunction, Supplier<M> mapFactory, Function<? super T, ? extends R> valueFunction, BiFunction<R, R, R> mergeFunction) {
        Map<E, R> map = mapFactory.get();
        consumer(t -> {
            E key = keyFunction.apply(t);
            R value = valueFunction.apply(t);
            if (Objects.isNull(key)) {
                throw new IllegalArgumentException("key is null ");
            }
            if (Objects.isNull(value)) {
                throw new IllegalArgumentException("value is null ");
            }
            if (map.containsKey(key) && Objects.nonNull(mergeFunction)) {
                R oldValue = map.get(key);
                value = mergeFunction.apply(oldValue, value);
            }
            map.put(key, value);
        });
        return map;
    }

    default <E, R> Map<E, List<R>> toGroup(Function<? super T, ? extends E> keyFunction, Function<? super T, ? extends R> valueFunction) {
        return toGroup(keyFunction, HashMap::new, valueFunction, ArrayList::new);
    }

    default <E, R, A extends Collection<R>, M extends Map<E, A>> Map<E, A> toGroup(Function<? super T, ? extends E> keyFunction, Supplier<M> mapFactory, Function<? super T, ? extends R> valueFunction, Supplier<A> collectionFactory) {
        Map<E, A> map = mapFactory.get();
        consumer(t -> {
            E key = keyFunction.apply(t);
            R value = valueFunction.apply(t);
            if (Objects.isNull(key)) {
                throw new IllegalArgumentException("key is null ");
            }
            if (Objects.isNull(value)) {
                throw new IllegalArgumentException("value is null ");
            }
            Collection<R> list = map.computeIfAbsent(key, k1 -> collectionFactory.get());
            if (Objects.nonNull(list)) {
                list.add(value);
            }
        });
        return map;
    }

    /**
     * 聚合
     *
     * @param identity
     * @param function
     * @param accumulator
     * @param <E>
     * @return
     */
    default <E> E reducing(E identity, Function<T, E> function, BinaryOperator<E> accumulator) {
        E result = identity;
        E[] arr = (E[]) new Object[1];
        arr[0] = result;
        consumer(t -> {
            E apply = function.apply(t);
            E result1 = accumulator.apply(arr[0], apply);
            arr[0] = result1;
        });
        return arr[0];
    }


    /**
     * 计数
     *
     * @return
     */
    default Long count() {
        return reducing(0L, t -> 1L, Long::sum);
    }

    /**
     * 最小值
     *
     * @param comparator
     * @return
     */
    default Optional<T> min(Comparator<T> comparator) {
        return Optional.ofNullable(sort(comparator).limit(1).toList()).map(list -> list.get(0));
    }

    /**
     * 最大值
     *
     * @param comparator
     * @return
     */
    default Optional<T> max(Comparator<T> comparator) {
        return Optional.ofNullable(sort(comparator.reversed()).limit(1).toList()).map(list -> list.get(0));
    }

    /**
     * 求和
     *
     * @return
     */
    default BigDecimal sum() {
        return reducing(BigDecimal.ZERO, t -> {
            if (t instanceof Short) {
                return new BigDecimal(((Short) t).toString());
            }
            if (t instanceof Integer) {
                return new BigDecimal(((Integer) t).toString());
            }
            if (t instanceof Long) {
                return new BigDecimal(((Long) t).toString());
            }
            if (t instanceof Double) {
                return new BigDecimal(((Double) t).toString());
            }
            if (t instanceof Float) {
                return new BigDecimal(((Float) t).toString());
            }
            if (t instanceof BigDecimal) {
                return (BigDecimal) t;
            }
            throw new IllegalArgumentException("not support type " + t.getClass().getName());
        }, BigDecimal::add);
    }

    /**
     * 平均值
     *
     * @param scale
     * @return
     */
    default BigDecimal average(int scale) {
        BigDecimal sum = sum();
        BigDecimal count = new BigDecimal(String.valueOf(count().longValue()));
        if (count.compareTo(BigDecimal.ZERO) == 0) {
            throw new IllegalArgumentException("count is zero");
        }
        return sum.divide(count, scale, BigDecimal.ROUND_HALF_UP);
    }

//    /**
//     * 分类聚合
//     *
//     * @param map
//     * @param <R>
//     * @return
//     */
//    default <R> Collection<Collection<R>> reduceByType(Map<Function<T, R>, Supplier<Collection<R>>> map) {
//        Map<Function<T, ?>, Collection<R>> listMap = new LinkedHashMap<>();
//        map.forEach((key, value) -> {
//            Collection<R> list = value.get();
//            listMap.put(key, list);
//        });
//        consumer(t -> {
//            map.forEach((key, value) -> {
//                R apply = key.apply(t);
//                if (Objects.nonNull(apply)) {
//                    Collection<R> list = listMap.get(key);
//                    list.add(apply);
//                }
//            });
//        });
//        return new ArrayList<>(listMap.values());
//    }

    /**
     * 分类聚合
     *
     * @param map
     * @param <R>
     * @return
     */
    default <R> List<List<R>> reduceByType(LinkedHashMap<Function<T, R>, List<R>> map) {
        consumer(t -> {
            map.forEach((key, value) -> {
                R apply = key.apply(t);
                if (Objects.nonNull(apply) && Objects.nonNull(value)) {
                    value.add(apply);
                }
            });
        });
        return new ArrayList<>(map.values());
    }

    /**
     * 匹配所有
     *
     * @param predicate
     * @return
     */
    default boolean allMatch(Predicate<T> predicate) {
        AtomicBoolean flag = new AtomicBoolean(true);
        consumerTillStop(t -> {
            if (!predicate.test(t)) {
                flag.set(false);
                stop();
            }
        });
        return flag.get();
    }

    /**
     * 任意匹配
     *
     * @param predicate
     * @return
     */
    default boolean anyMatch(Predicate<T> predicate) {
        AtomicBoolean flag = new AtomicBoolean(false);
        consumerTillStop(t -> {
            if (predicate.test(t)) {
                flag.set(true);
                stop();
            }
        });
        return flag.get();
    }

    /**
     * 不匹配
     *
     * @param predicate
     * @return
     */
    default boolean noneMatch(Predicate<T> predicate) {
        AtomicBoolean flag = new AtomicBoolean(true);
        consumerTillStop(t -> {
            if (predicate.test(t)) {
                flag.set(false);
                stop();
            }
        });
        return flag.get();
    }
}
